﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSScriptLibrary;
using System.Reflection;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Security;
using System.Security.Permissions;
using csscript;

public interface ISum
{
    int Sum(int a, int b);
}

namespace Testpad
{
    class Program
    {
        static void LoadAssemblyForreflection()
        {

            CSScriptLibrary.AssemblyResolver.IsNamespaceDefinedInAssembly(@"F:\cs-script\engine\Testpad\test.dll", "scripting");
        }

        static void CompileWithDoc()
        {
            string asmFile = CSScript.CompileWithConfig(
                                    @"E:\My Dropbox\Public\Marco Singer\test.cs",
                                    null,
                                    false,
                                    CSScript.GlobalSettings,
                                    @"/doc:""E:\My Dropbox\Public\Marco Singer\test.xml""");

            var asm = Assembly.LoadFrom(asmFile);
        }

        static void CompilerSwallowsErrors()
        {
            CSharpCodeProvider codeProvider = new CSharpCodeProvider();

            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.OutputAssembly = Path.GetTempFileName();
            //parameters.CompilerOptions = "/warnaserror";
            CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters,
                                                      @"class Test
                                                        {
                                                            int TestMethod()
                                                            { 
                                                                return 5;
                                                                return 10;
                                                            } 
                                                        }");
            foreach (var e in results.Errors)
                Trace.WriteLine(e.ToString());

        }

        static void ExecuteInSandbox(PermissionSet permissionSet, Action action)
        {
            permissionSet.PermitOnly();
            try
            {
                action();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
            }
            finally
            {
                CodeAccessPermission.RevertPermitOnly();
            }
        }
        static void ResourcesTest()
        {
            var script = CSScript.Load(@"P:\My Dropbox\Public\Leo Meyer\ScriptA.cs");
        }
        static void Main(string[] args)
        {
            ResourcesTest();

            var CreateSomeFile = CSScript.LoadMethod(
                        @"using System.IO;
                          public static void Test()
                          {
                              using (var f = File.Open(""somefile.txt"", FileMode.OpenOrCreate))
                                  Console.WriteLine(""File.Open: success"");
                          }")
                         .GetStaticMethod();

            var permissionSet = new PermissionSet(PermissionState.None);
            permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

            CreateSomeFile();

            //Sandbox.Execute(permissionSet, () =>
            //{
            //    CreateSomeFile();
            //});

            Sandbox.With(SecurityPermissionFlag.AllFlags)
                   .Execute(() =>
                            {
                                try
                                {

                                    CreateSomeFile();
                                }
                                catch(Exception e)
                                {
                                    Console.WriteLine(e.Message);
                                }
                            });

            CreateSomeFile();

            //CompileWithDoc(); return;

            //             string code1 =
            //                               @"static public int Sum(int a, int b) 
            //                                 {
            //                                     #warning test warning
            //                                     return a + b;                    
            //                                 }";
//try
//{
//    string script = Path.GetTempFileName();
//    File.WriteAllText(script, code1);

//    string assembly = CSScript.CompileWithConfig(script, null, false, CSScript.GlobalSettings, "/warnaserror");
//}
//catch (Exception e)
//{
//    Console.WriteLine(e.Message);
//}
            //compiler detailed error

            {


                try
                {
                    CSScript.LoadCode("invalid code");
                }
                catch (Exception e)
                {
                    CompilerErrorCollection errors = (CompilerErrorCollection)e.Data["Errors"];
                    foreach (CompilerError err in errors)
                    {
                        Console.WriteLine("{0}({1},{2}): {3} {4}: {5}",
                            err.FileName, err.Line, err.Column, err.IsWarning ? "warning" : "error", err.ErrorNumber, err.ErrorText);
                    }
                }

            }
            {
                string code =
                    //@"//css_co /warnaserror+;
                                @"static public int Sum(int a, int b) 
                                  {
                                      #warning test warning
                                      return a + b; 

                                      return 7;                   
                                  }";
                try
                {
                    CSScript.LoadMethod(code);

                    FileInfo scriptInfo = CSScript.CompilingHistory.Last().Key;
                    CompilerErrorCollection errors = CSScript.CompilingHistory.Last().Value.Errors;

                    StringBuilder compileErr = new StringBuilder();
                    foreach (CompilerError err in errors)
                    {
                        Console.Write(err.FileName);
                        Console.Write("(");
                        Console.Write(err.Line);
                        Console.Write(",");
                        Console.Write(err.Column);
                        Console.Write("): ");
                        if (err.IsWarning)
                            Console.Write("warning ");
                        else
                            Console.Write("error ");
                        Console.Write(err.ErrorNumber);
                        Console.Write(": ");
                        Console.Write(err.ErrorText);
                        Console.WriteLine();
                    }
                }
                catch (Exception e)
                {
                    Trace.WriteLine(e.Message);
                    CompilerErrorCollection errors = (CompilerErrorCollection)e.Data["Errors"];

                    StringBuilder compileErr = new StringBuilder();
                    foreach (CompilerError err in errors)
                    {
                        Console.Write(err.FileName);
                        Console.Write("(");
                        Console.Write(err.Line);
                        Console.Write(",");
                        Console.Write(err.Column);
                        Console.Write("): ");
                        if (err.IsWarning)
                            Console.Write("warning ");
                        else
                            Console.Write("error ");
                        Console.Write(err.ErrorNumber);
                        Console.Write(": ");
                        Console.Write(err.ErrorText);
                        Console.WriteLine();
                    }
                }
            }
            return;
            string scriptCode = @"//css_co /define:TESTING;
                                  static public int Sum(int a, int b) 
                                  {          
                                    #if TESTING
                                      return 7;                    
                                    #else           
                                      return a + b;                    
                                    #endif                       
                                  }";

            //var Sum = CSScript.LoadCode(scriptCode)
            //                  .GetStaticMethodWithArgs("*.Sum", typeof(int), typeof(int));


            var dir = csscript.CSSEnvironment.GetCacheDirectory(Path.Combine(Path.GetTempPath(), "CSSCRIPT\\dummy.cs"));
            CSScript.CacheEnabled = false;

            var Sum = CSScript.LoadMethod(scriptCode)
                              .GetStaticMethodWithArgs("*.Sum", typeof(int), typeof(int));


            var result7 = Sum(1, 4);

            SumLocal(1, 2);
            var t1 = CSScriptLibrary.AssemblyResolver.FindLocalAssembly("test.xml", @"F:\cs-script\engine\Testpad");

            //var aa = Assembly.ReflectionOnlyLoadFrom(@"F:\cs-script\engine\Testpad\test.dll");

            //LoadAssemblyForreflection();
            //GC.Collect();
            //MessageBox.Show("test");
            return;
            var t = CSScriptLibrary.AssemblyResolver.FindLocalAssembly("System.Xml", "c:\\windows\\microsoft.net\\framework\\v2.0.50727");

            var result = SumLocal(1, 2);
            var result1 = SumLocal(1, 3);
            var result2 = SumRemote(1, 2);
        }

        static int SumRemote(int a, int b)
        {
            //this will also unload and delete the compiled assembly file after the execution
            string scriptCode = @"using System;
                                  public class Calc : MarshalByRefObject
                                  {                                      
                                     public int Sum(int a, int b) 
                                     {                                   
                                        return a + b;                    
                                     }                                   
                                  }";

            string asmFile = CSScript.CompileCode(scriptCode, null, false);
            using (AsmHelper helper = new AsmHelper(asmFile, "tempDomain", true))
            {
                //The following code will always fail as obj is a Remoting TransparentProxy and 
                //it does not have members of ISum.
                //object obj = helper.CreateObject("Calc");
                //ISum calc = obj.AlignToInterface<ISum>(); 

                //The following code will always secceed as the aligning will be conducted in the remote 
                //AppDomain where the object was created
                ISum calc = helper.CreateAndAlignToInterface<ISum>("Calc");

                return calc.Sum(a, b);
            }
        }

        static int SumLocal(int a, int b)
        {
            string scriptCode = @"//css_args /co:/define TTT;
                                  using System;                    
                                  public class Calc                      
                                  {                                      
                                     public int Sum(int a, int b) 
                                     {                                   
                                        return a + b;                    
                                     }                                   
                                  }";

            ISum calc = CSScript.LoadCode(scriptCode, null, false)
                                .CreateInstance("Calc")
                                .AlignToInterface<ISum>();

            return calc.Sum(a, b);
        }
    }
}

//public class ILReader  : IEnumerable<ILInstruction>
//{
//   Byte[] m_byteArray;
//   Int32 m_position;
//   MethodBase m_enclosingMethod;

//   static OpCode[] s_OneByteOpCodes = new OpCode[0x100];
//   static OpCode[] s_TwoByteOpCodes = new OpCode[0x100]; 
//   static ILReader()
//   {
//     foreach (FieldInfo fi in typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static))
//     {
//       OpCode opCode = (OpCode)fi.GetValue(null);
//       UInt16 value = (UInt16)opCode.Value;
//       if (value < 0x100)
//         s_OneByteOpCodes[value] = opCode;
//       else if ((value & 0xff00) == 0xfe00)
//         s_TwoByteOpCodes[value & 0xff] = opCode;
//     }
//   }

//   public ILReader(MethodBase enclosingMethod)
//   {
//     this.m_enclosingMethod = enclosingMethod;
//     MethodBody methodBody = m_enclosingMethod.GetMethodBody();
//     this.m_byteArray = (methodBody == null) ? new Byte[0] : methodBody.GetILAsByteArray();
//     this.m_position = 0;
//   }

//   public IEnumerator<ILInstruction>GetEnumerator()
//   {
//     while (m_position < m_byteArray.Length)
//       yield return Next();

//     m_position = 0;
//     yield break;
//   }
//   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()  { return this.GetEnumerator(); }

//   ILInstruction Next()
//   {
//     Int32 offset = m_position;
//     OpCode opCode = OpCodes.Nop;
//     Int32 token = 0;

//     // read first 1 or 2 bytes as opCode
//     Byte code = ReadByte();
//     if (code != 0xFE)
//       opCode = s_OneByteOpCodes[code];
//     else
//     {
//       code = ReadByte();
//       opCode = s_TwoByteOpCodes[code];
//     }

//     switch (opCode.OperandType)
//     {
//       case OperandType.InlineNone:
//         return new InlineNoneInstruction(m_enclosingMethod, offset, opCode);

//       case OperandType.ShortInlineBrTarget:
//         SByte shortDelta = ReadSByte();
//         return new ShortInlineBrTargetInstruction(m_enclosingMethod, offset, opCode, shortDelta);

//       case OperandType.InlineBrTarget: Int32 delta = ReadInt32();     return new ...;
//       case OperandType.ShortInlineI:   Byte int8 = ReadByte();        return new ...;
//       case OperandType.InlineI:        Int32 int32 = ReadInt32();     return new ...;
//       case OperandType.InlineI8:       Int64 int64 = ReadInt64();     return new ...;
//       case OperandType.ShortInlineR:   Single float32 = ReadSingle(); return new ...;
//       case OperandType.InlineR:        Double float64 = ReadDouble(); return new ...;
//       case OperandType.ShortInlineVar: Byte index8 = ReadByte();      return new ...;
//       case OperandType.InlineVar:      UInt16 index16 = ReadUInt16(); return new ...;
//       case OperandType.InlineString:   token = ReadInt32(); return new ...;
//       case OperandType.InlineSig:      token = ReadInt32(); return new ...;
//       case OperandType.InlineField:    token = ReadInt32(); return new ...;
//       case OperandType.InlineType:     token = ReadInt32(); return new ...;
//       case OperandType.InlineTok:      token = ReadInt32(); return new ...;

//       case OperandType.InlineMethod:
//         token = ReadInt32();
//         return new InlineMethodInstruction(m_enclosingMethod, offset, opCode, token);

//       case OperandType.InlineSwitch:
//         Int32 cases = ReadInt32();
//         Int32[] deltas = new Int32[cases];
//         for (Int32 i = 0; i < cases; i++) deltas[i] = ReadInt32();
//         return new InlineSwitchInstruction(m_enclosingMethod, offset, opCode, deltas);

//       default:
//         throw new BadImageFormatException("unexpected OperandType " + opCode.OperandType);
//     }
//   }

//   Byte ReadByte() { return (Byte)m_byteArray[m_position++]; }
//   SByte ReadSByte() { return (SByte)ReadByte(); }

//   UInt16 ReadUInt16() { m_position += 2; return BitConverter.ToUInt16(m_byteArray, m_position - 2); }
//   UInt32 ReadUInt32() { m_position += 4; return BitConverter.ToUInt32(m_byteArray, m_position - 4); }
//   UInt64 ReadUInt64() { m_position += 8; return BitConverter.ToUInt64(m_byteArray, m_position - 8); }

//   Int32 ReadInt32() { m_position += 4; return BitConverter.ToInt32(m_byteArray, m_position - 4); }
//   Int64 ReadInt64() { m_position += 8; return BitConverter.ToInt64(m_byteArray, m_position - 8); }

//   Single ReadSingle() { m_position += 4; return BitConverter.ToSingle(m_byteArray, m_position - 4); }
//   Double ReadDouble() { m_position += 8; return BitConverter.ToDouble(m_byteArray, m_position - 8); }
//} 